from lib     import *
from demo    import *
from fastmap import *
from table   import *
from fastmap import *
import random

def showRows(o,leafp,n,pre,data):
  if leafp:
    print "\n"
    for one in data:
      print '   '*n+pre,data
  else: print "\n"

def showAliens(o,leafp,n,pre,data):
  print ": "+str(o.info) if o.info else ""
   
class Dendogram():
  def __init__(o,t,info) : 
    o.table=t; o.l=o.r=None; o.info=info
  def resetCounts(o):
    if o.info:
      o.info.resetCounts()
  def become(o1,o2):
    o2.table = o1.table
    o2.l     = o1.l
    o2.r     = o1.r
    o2.info  = o1.info
  def show(o,n=0,pre=":",extra=noop):
     prin('|..' * n + pre,len(o.table.data))
     extra(o,not o.l or not o.r,n,pre,o.table.data)
     if o.l:  o.l.show(n+1,"<",extra)
     if o.r:  o.r.show(n+1,">",extra)
  def map(o,fn) :
     out = fn(o)
     if   o.isLeaf() : return out
     if o.l: return o.l.map(fn)
     if o.r: return o.r.map(fn)
  def near(o,data):
    path=[]
    out = o.near1(o.table.rowProxy(data),path)
    o.patch(path)
    return out
  def near1(o,data,path):
    if   o.isLeaf()        : return o.table
    path.append(o)
    if   o.info.leftp(data): return o.l.near1(data,path)
    else                   : return o.r.near1(data,path)
  def isLeaf(o) : return not o.info   
  def patch(o,path,p=0.2) :
    for n,step in enumerate(path):
      if step.info.misfits() > p:
        if len(step.table.data) > 20:
          print "Patching p",step.info.misfits(),n,len(step.table.data)    
          todo=[row.data for row in step.table.data]
          t= step.table.clone(todo)
          step.become(rrsl(t))
          break 

def rrsl(t,minObs=4,enough=0, use=10**32,
         about=FastMap,lives=2,prune=0.5):
  def recurse(t,lives,n,pre):
    #print "|.."*n + pre, len(t.data)
    if len(t.data) < enough and lives < 1: 
      return Dendogram(t,None)
    info   = about(t,enough*2-1)
    tree   = Dendogram(t,info)
    tree.l = recurse(t.clone(info.l), lives-1,n+1,"<")
    tree.r = recurse(t.clone(info.r), lives-1,n+1,">")
    return tree
  enough = enough or max(minObs,len(t.data)**prune)
  return recurse(t,lives,0,":")
